﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Xml;

namespace Utils
{
    public static class DictionaryHelper
    {
        public static E TryGetKeyByValue<E, T>(this IDictionary<E, T> dict, T value)
        {
            return TryGetKeyByValue(dict, value, default);
        }

        public static E TryGetKeyByValue<E, T>(this IDictionary<E, T> dict, T value, E defaultKey)
        {
            foreach (var (key, keyValue) in dict)
            {
                if (keyValue.Equals(value))
                {
                    return key;
                }
            }
            return defaultKey;
        }
        /// <summary>
        /// 获取值
        /// </summary>
        /// <typeparam name="E"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="dict"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T TryGetValue<E, T>(this IDictionary<E, T> dict, E key)
        {
            return TryGetValue(dict, key, default);
        }

        public static T TryGetValue<E, T>(this IDictionary<E, T> dict, E key, T default_value)
        {
            if (dict.ContainsKey(key))
            {
                return dict[key];
            }
            return default_value;
        }

        public static T ToEntity<T>(this IDictionary<string, string> dict)
        {
            return dict.ToDictionary(a => a.Key, a => (object)a.Value).ToEntity<T>();
        }
        /// <summary>
        /// 转实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static T ToEntity<T>(this IDictionary<string, object> dict)
        {
            try
            {
                var t = typeof(T);
                object obj = t.Assembly.CreateInstance(t.FullName);
                var propers = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                foreach (var item in propers)
                {
                    var attrs = item.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    var propertyName = item.Name;
                    if (attrs != null && attrs.Length > 0)
                    {
                        var attr = attrs[0] as DescriptionAttribute;
                        propertyName = attr.Description;
                    }
                    if (dict.ContainsKey(propertyName))
                    {
                        var value = dict[propertyName];
                        if (item.PropertyType.TryChangeType(ref value))
                        {
                            item.SetValue(obj, value, null);
                        }
                    }
                }
                return (T)obj;
            }
            catch (Exception)
            {
                throw new InvalidCastException("无法转化:DictionaryHelper.ToEntity");
            }
        }

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="appends"></param>
        public static void AddRange<K, V>(this IDictionary<K, V> dictionary, IEnumerable<KeyValuePair<K, V>> appends)
        {
            if (appends == null) return;
            foreach (var item in appends)
            {
                dictionary.Add(item.Key, item.Value);
            }
        }

        /// <summary>
        /// 转键值对
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<string, object> ToDictionary<T>(this T obj) where T : class
        {
            var dict = new Dictionary<string, object>();
            if (obj == null)
                return dict;
            if (obj is IDictionary append)
            {
                foreach (DictionaryEntry item in append)
                {
                    dict.Add(item.Key.ToString(), item.Value);
                }
                return dict;
            }
            PropertyInfo[] ps = obj.GetType().GetProperties();
            foreach (var p in ps)
            {
                dict.Add(p.Name, p.GetValue(obj, null));
            }
            return dict;
        }

        /// <summary>
        /// 转url参数
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static string ToUrlQuery<V>(this IEnumerable<KeyValuePair<string, V>> dictionary, bool encode = true)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var kv in dictionary)
            {
                if (kv.Value != null)
                {
                    sb.Append($"{kv.Key}={(encode ? StringHelper.UrlEncode(kv.Value.ToString()) : kv.Value.ToString())}&");
                }
            }
            return sb.ToString().TrimEnd('&');
        }
        /// <summary>
        /// 键值对转 字典
        /// </summary>
        /// <param name="query"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static IDictionary<string, string> QueryToDictionary(this string query, bool encode = true)
        {
            StringBuilder sb = new StringBuilder();
            return query.Split("&", StringSplitOptions.RemoveEmptyEntries)
                  .Select(a => a.Split("="))
                  .ToDictionary(a => a[0], a => a.Length > 1 ? (StringHelper.UrlDecode(a[1])) : "");
        }

        /// <summary>
        /// 将xml转为字典对象
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static IDictionary<string, string> XmlToDictionary(this string xml)
        {
            if (string.IsNullOrEmpty(xml)) return null;
            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);
            xmlDoc.XmlResolver = null;
            var xmlNode = xmlDoc.LastChild;//获取到根节点<xml>
            var nodes = xmlNode.ChildNodes;
            var dict = new SortedDictionary<string, string>();
            foreach (XmlNode node in nodes)
            {
                var element = (XmlElement)node;
                dict.Add(element.Name, element.InnerText);
            }
            return dict;
        }



    }
}
